package com.sheepone.distributor.listener;

import com.sheepone.distributor.anno.Skip;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Miss.杨
 * @description
 * @since 2024/1/26 - 15:10
 */
public class DistributorListenerMasker {
    private static Map<Class<? extends DistributorListener>, Integer> MASKS =new ConcurrentHashMap<>();

    private static final Logger logger = LoggerFactory.getLogger(new Object(){}.getClass().getEnclosingClass());
    public static final int MASK_SKIP = 0;
    public static final int MASK_BEFORE_STARTING = 1 << 1;
    public static final int MASK_AFTER_STARTING = 1 << 2;
    public static final int MASK_BEFORE_STOPPING = 1 << 3;
    public static final int MASK_AFTER_STOPPING = 1 << 4;

    private static final int MASK_ALL =  MASK_BEFORE_STARTING |
            MASK_AFTER_STARTING | MASK_BEFORE_STOPPING | MASK_AFTER_STOPPING;

    static int mask(Class<? extends DistributorListener> clazz) {
        Integer mask = MASKS.get(clazz);
        if (mask == null) {
            mask = mask0(clazz);
            MASKS.put(clazz, mask);
        }

        return mask;
    }

    private static int mask0(Class<? extends DistributorListener> listenerType) {
        
        int mask = MASK_ALL;
        if (isSkippable(listenerType, "beforeStarting")) {
            mask &= ~MASK_BEFORE_STARTING;
        }
        if (isSkippable(listenerType, "afterStarting")) {
            mask &= ~MASK_AFTER_STARTING;
        }
        if (isSkippable(listenerType, "beforeStopping")) {
            mask &= ~MASK_BEFORE_STOPPING;
        }
        if (isSkippable(listenerType, "afterStopping")) {
            mask &= ~MASK_AFTER_STOPPING;
        }

        return mask;
    }


    private static boolean isSkippable(final Class<?> listenerType, final String methodName) {
        Method m;
        try {
            m = listenerType.getMethod(methodName);
        } catch (NoSuchMethodException e) {
            if (logger.isDebugEnabled()) {
                logger.debug("Class {} missing method {}, assume we can not skip execution", listenerType, methodName, e);
            }
            return false;
        }
        return m.isAnnotationPresent(Skip.class);
    }

}
